using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SharpMud.Server.App.Hosting;

namespace SharpMud.Server.App.GUI
{
    public partial class MainForm : Form
    {
        private ApplicationHost                 AppHost;
        private IAppExecutionHandle             AppExecutionHandle;
        private ApplicationHostConfiguration    AppHostConfiguration;

        #region Construction and Initialization
        public MainForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            RefreshFormCaption();

            log4net.Layout.ILayout defaultLayout = new log4net.Layout.PatternLayout
                (   "%-5level| %logger{1}> %message%newline"    );
            log4net.Appender.IAppender defaultAppender = new TextBoxLogAppender(defaultLayout,txtLog);
            log4net.Config.BasicConfigurator.Configure(defaultAppender);

            if (Server.App.GUI.Properties.Settings.Default != null)
                if (Server.App.GUI.Properties.Settings.Default.ApplicationHostConfiguration != null)
                    this.InitializeServer(Server.App.GUI.Properties.Settings.Default.ApplicationHostConfiguration);
        }

        private void InitializeServer(ApplicationHostConfiguration appHostConfig)
        {
            if (appHostConfig == null)
            {
                throw new ArgumentNullException("appHostConfig");
            }
            if (this.AppExecutionHandle != null)
            {
                if (this.CurrentAppStatus != AppStatus.Disposed
                && this.CurrentAppStatus != AppStatus.UnInitialized
                && this.CurrentAppStatus != AppStatus.Initialized
                && this.CurrentAppStatus != AppStatus.Stopped)
                {
                    throw new InvalidOperationException("Cannot re-configure Application Host while an Application is running.");
                }
                if (this.CurrentAppStatus == AppStatus.Initialized
                || this.CurrentAppStatus == AppStatus.Stopped)
                {
                    this.AppExecutionHandle.Dispose();
                }
                this.AppExecutionHandle = null;
                this.AppHost.Dispose();
                this.AppHost = null;
                this.RefreshFormCaption();
                this.RefreshExecutionButtons();
            }
            ClearVisibleLog();
            this.AppHostConfiguration = appHostConfig;
            this.AppHost = new ApplicationHost();
            this.AppHost.LoadConfiguration(appHostConfig);
            this.AppHost.Initialize();
            this.AppExecutionHandle = this.AppHost.CreateAppExecHandle();
            this.AppExecutionHandle.StatusChanged += new AppStatusChangeHandler(App_StatusChanged);
            this.RefreshFormCaption();
            this.RefreshExecutionButtons();
        }
        private void InitializeServer()
        {
            InitializeServer(Server.App.GUI.Properties.Settings.Default.ApplicationHostConfiguration);
        }
        private void ClearVisibleLog()
        {
            txtLog.Clear();
        }
        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (this.AppExecutionHandle != null)
            {
                this.AppExecutionHandle.Dispose();
                this.AppExecutionHandle = null;
            }
            if (this.AppHost != null)
            {
                this.AppHost.Dispose();
            }
        }
        #endregion

        private void Update()
        {
            RefreshFormCaption();
            RefreshExecutionButtons();
            RefreshManagementTab();
        }

        private void RefreshManagementTab()
        {
            if (this.AppExecutionHandle.Status == AppStatus.Disposed ||
                this.AppExecutionHandle.Status == AppStatus.Disposing)
            {
                propertyGrid.Enabled = false;
                propertyGrid.SelectedObject = null;
                return;
            }
            else
            {
                propertyGrid.Enabled = true;
                propertyGrid.SelectedObject = this.AppHost.App;
                return;
            }
        }

        private void App_StatusChanged(Application sender, AppStatusChangeEventArgs e)
        {
            this.Invoke(new MethodInvoker(Update));
        }

        public AppStatus CurrentAppStatus
        {
            get
            {
                if (this.AppExecutionHandle == null)
                    throw new InvalidOperationException("Cannot retrieve Application status when an Application Execution Handle is not present.");
                return this.AppExecutionHandle.Status;
            }
        }

        public void RefreshFormCaption()
        {
            if (this.AppHost == null)
            {
                this.Text = "SharpMUD Server - [No MudLib Loaded]";
                return;
            }
            else if (this.AppExecutionHandle == null)
            {
                this.Text = "SharpMUD Server - [No MudLib Loaded]";
                return;
            }
            else if (this.AppHostConfiguration == null)
            {
                this.Text = "SharpMUD Server - [No MudLib Loaded]";
                return;
            }
            else
            {
                string mudlibTitle = String.Empty;
                mudlibTitle = MudLib.Metadata.MudLibMetadata.FromAssembly(this.AppHostConfiguration.ServerAppLocation.AcquireAssembly()).MudLibTitle;
                if (mudlibTitle == String.Empty) mudlibTitle = this.AppHostConfiguration.ServerAppLocation.FullTypeName;
                this.Text = "SharpMUD Server - [" + this.AppExecutionHandle.Status.ToString() + "] - " + mudlibTitle;
                return;
            }
        }
        public void RefreshExecutionButtons()
        {
            this.exitToolStripMenuItem.Enabled = true;
            if (this.AppExecutionHandle == null
                || this.AppHost == null
                || this.AppHostConfiguration == null)
            {
                this.opendefaultToolStripMenuItem.Enabled = (Server.App.GUI.Properties.Settings.Default != null);
                this.openToolStripMenuItem.Enabled = true;
                this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                this.Pause_toolStripButton.Enabled = false;
                this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                return;
            }
            switch (this.CurrentAppStatus)
            {
                case AppStatus.UnInitialized:
                    this.opendefaultToolStripMenuItem.Enabled = (Server.App.GUI.Properties.Settings.Default != null);
                    this.openToolStripMenuItem.Enabled = true;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = true;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Initializing:
                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Initialized:
                    this.opendefaultToolStripMenuItem.Enabled = true;
                    this.openToolStripMenuItem.Enabled = true;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = true;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Starting:
                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Running:

                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = true;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = true;
                    break;
                case AppStatus.Pausing:

                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Paused:

                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = true;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = true;
                    break;
                case AppStatus.Resuming:
                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Stopping:
                    this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Stopped:
                    this.opendefaultToolStripMenuItem.Enabled = (Server.App.GUI.Properties.Settings.Default != null);;
                    this.openToolStripMenuItem.Enabled = true;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = true;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Disposing: this.opendefaultToolStripMenuItem.Enabled = false;
                    this.openToolStripMenuItem.Enabled = false;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
                case AppStatus.Disposed: 
                    this.opendefaultToolStripMenuItem.Enabled = true;
                    this.openToolStripMenuItem.Enabled = true;
                    this.Start_toolStripButton.Enabled = this.startToolStripMenuItem.Enabled = false;
                    this.Pause_toolStripButton.Enabled = false;
                    this.Stop_toolStripButton.Enabled = this.stopToolStripMenuItem.Enabled = false;
                    break;
            }
        }

        #region Buttons and Menus

        private void opendefaultToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _OpenDefault();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Open();
        }

        private void saveasToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _SaveAs();
        }

        private void startToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Start();
        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Stop();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _Exit();
        }

        private void Start_toolStripButton_Click(object sender, EventArgs e)
        {
            _Start();
        }

        private void Pause_toolStripButton_Click(object sender, EventArgs e)
        {
            _Pause();
        }

        private void Stop_toolStripButton_Click(object sender, EventArgs e)
        {
            _Stop();
        }
        #endregion

        private void _Start()
        {
            if (this.CurrentAppStatus == AppStatus.Paused)
            { this.AppExecutionHandle.Resume(); return; }
            else if (this.CurrentAppStatus == AppStatus.UnInitialized)
                this.AppExecutionHandle.Initialize();

            if ((this.CurrentAppStatus == AppStatus.Initialized) || (this.CurrentAppStatus == AppStatus.Stopped))
            { this.AppExecutionHandle.Start(); this.RefreshExecutionButtons(); return; }

            throw new InvalidOperationException();
        }
        private void _Stop()
        {
            this.AppExecutionHandle.Stop();
        }
        private void _Pause()
        {
            this.AppExecutionHandle.Pause();
        }
        private void _Exit()
        {
            this.Close();
        }
        private void _SaveAs()
        {
            if (this.AppHostConfiguration == null)
                throw new InvalidOperationException();

            Server.App.GUI.Properties.Settings settings = Server.App.GUI.Properties.Settings.Default;
            settings.ApplicationHostConfiguration = this.AppHostConfiguration;
            settings.Save();
        }
        private void _OpenDefault()
        {
            this.InitializeServer(Server.App.GUI.Properties.Settings.Default.ApplicationHostConfiguration);
        }
        private void _Open()
        {
            OpenFileDialog openFileDlg = new OpenFileDialog();
            System.Reflection.Assembly loadedAssembly = null;
            System.Type mudlibType = null;

            openFileDlg.Title = "Open MudLib";
            openFileDlg.CheckFileExists = true;
            openFileDlg.CheckPathExists = true;
            openFileDlg.Filter = "Class Library Assembly (*.dll)|*.dll|Executable Assembly (*.exe)|*.exe";
            openFileDlg.RestoreDirectory = true;

            while (loadedAssembly == null)
            {
                openFileDlg.FileName = String.Empty;
                DialogResult dlgResult = openFileDlg.ShowDialog();
                if (dlgResult != DialogResult.OK)
                    return;
                else
                {
                    try
                    {
                        loadedAssembly = System.Reflection.Assembly.LoadFile(openFileDlg.FileName);
                    }
                    catch (System.Exception e)
                    {
                        MessageBox.Show("Error loading assembly:" + System.Environment.NewLine + e.ToString(), "Error Loading Assembly", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                if (loadedAssembly == null) continue;
                if (!MudLib.Metadata.MudLibMetadata.HasValidMudLib(loadedAssembly))
                {
                    MessageBox.Show("The given Assembly does not have a valid MudLib defined within it.", "Error Loading MudLib", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    loadedAssembly = null;
                    continue;
                }
                MudLib.Metadata.MudLibMetadata mudlibMetadata = MudLib.Metadata.MudLibMetadata.FromAssembly(loadedAssembly);

                ApplicationHostConfiguration ahc = this.AppHostConfiguration;
                ahc.ServerAppLocation = SharpMud.DynamicTyping.AssembliedTypeLocation.FromLoadedType(mudlibMetadata.MudLibRoot);
                InitializeServer(ahc);
                return;
            }
        }
    }
}